package com.le.tester.imooc.oldfairy.concurrent;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * createTime：2023/6/15 9:21
 * description：reentrantLock
 */
public class DiningPhilosophersSample implements Runnable {

    ReentrantLock lock = new ReentrantLock();
    int[] forks = new int[5];
    Condition[] waitForks = new Condition[5];

    Condition wait = lock.newCondition();
    Phi[] phis = new Phi[5];
    boolean[] dirty = new boolean[5];

    public DiningPhilosophersSample() {
        for (int i = 0; i < 5; i++) {
            phis[i] = new Phi(i + 1);
            dirty[i] = true;
            waitForks[i] = lock.newCondition();
        }
    }


    class Phi extends Philosopher {

        public Phi(int id) {
            super(id);
        }

        @Override
        public void run() {
            while (true) {
                try {
//     1--avg speed is 35,不加上锁执行
//                    this.thinking();
//                    this.takeLeft(forks);
//                    this.takeRight(forks);
//                    this.eating();
//                    this.putLeft(forks);
//                    this.putRight(forks);
//                    this.finished();

//                    2-- avg speed is 9,全部锁住执行
//                    lock.lockInterruptibly();
//                    this.thinking();
//                    this.takeLeft(forks);
//                    this.takeRight(forks);
//                    this.eating();
//                    this.putLeft(forks);
//                    this.putRight(forks);
//                    this.finished();
//                    lock.unlock();

//                    3--减少锁的范围，尝试不锁住thinking,avg is 15
//                    this.thinking();
//                    lock.lockInterruptibly();
//                    this.takeLeft(forks);
//                    this.takeRight(forks);
//                    this.eating();
//                    this.putLeft(forks);
//                    this.putRight(forks);
//                    this.finished();
//                    lock.unlock();

                    //                    4--继续减少锁的范围，只有锁住takeLeft和takeRight,avg is 25,
                    //                    但是在takeLeft的时候，并不能保证执行成功，那么互斥锁将不能被释放
//                    this.thinking();
//                    lock.lockInterruptibly();
//                    this.takeLeft(forks);
//                    this.takeRight(forks);
//                    lock.unlock();
//                    this.eating();
//                    this.putLeft(forks);
//                    this.putRight(forks);
//                    this.finished();、
                    //5--循环尝试拿起fork,avg is 7
//                    this.thinking();
//                    lock.lockInterruptibly();
////                    this.takeLeft(forks);
////                    this.takeRight(forks);
//                    while (!this.takeLeft(forks)) {
//                        //减少一下cpu负载
//                        Thread.sleep(1);
//
//                    }
//                    while (!this.takeRight(forks)) {
//                        Thread.sleep(1);
//                    }
//                    lock.unlock();
//                    this.eating();
//                    this.putLeft(forks);
//                    this.putRight(forks);
//                    this.finished();

                    //6--bug try,dead lock,left wait right
//                    this.thinking();
//                    lock.lockInterruptibly();
//                    while (!this.takeLeft(forks)) {
//                        //减少一下cpu负载
//                        Thread.sleep(1);
//
//                    }
//                    while (!this.takeRight(forks)) {
//                        Thread.sleep(1);
//                    }
//                    lock.unlock();
//                    this.eating();
//
//                    //上面的lock还在循环，并没有释放锁，这里继续尝试想要获取锁
//                    //lock.lockInterruptibly();
//                    this.putLeft(forks);
//                    this.putRight(forks);
//                    //lock.unlock();
//                    this.finished();

//                    7--增加checkLeft or checkRight
//                    this.thinking();
//                    lock.lockInterruptibly();
//                    if (!(this.checkLeft(forks) && this.checkRight(forks))) {
//                        lock.unlock();
//                        continue;
//                    }
//                    this.takeLeft(forks);
//                    this.takeRight(forks);
//                    lock.unlock();
//                    this.eating();
//
//                    lock.lockInterruptibly();
//                    this.putLeft(forks);
//                    this.putRight(forks);
//                    lock.unlock();
//                    this.finished();


                    //                    8--使用Lock--Condition
//                    this.thinking();
//                    lock.lockInterruptibly();
//
//                    while (!this.takeLeft(forks)) {
//                        //更少的占用cpu
//                        //waitForks[this.left()].await();
//
//                        wait.await();
//                    }
//
//                    while (!this.takeRight(forks)) {
//                        //更少的占用cpu
//                        //waitForks[this.right()].await();
//                        wait.await();
//                    }
////                    if (!(this.checkLeft(forks) && this.checkRight(forks))) {
////                        lock.unlock();
////                        continue;
////                    }
////                    this.takeLeft(forks);
////                    this.takeRight(forks);
//                    lock.unlock();
//                    this.eating();
//
//                    lock.lockInterruptibly();
//                    this.putLeft(forks);
//                    this.putRight(forks);
//                    //await 等待着singleAll
//                    //waitForks[this.left()].signalAll();
//                    //waitForks[this.right()].signalAll();
//                    wait.signalAll();
//                    lock.unlock();
//                    this.finished();

                    //9--使用check版本
//                    this.thinking();
//                    lock.lockInterruptibly();
//                    while (!(this.checkLeft(forks) && this.checkRight(forks))) {
//                        wait.await();
//                    }
//
//                    this.takeLeft(forks);
//                    this.takeRight(forks);
//                    lock.unlock();
//                    this.eating();
//
//                    lock.lockInterruptibly();
//                    this.putLeft(forks);
//                    this.putRight(forks);
//                    wait.signalAll();
//                    lock.unlock();
//                    this.finished();

                    //10--允许哲学家主动让出fork
                    this.thinking();
                    lock.lockInterruptibly();

                    boolean takeLeft = this.checkLeft(forks);
                    if (!takeLeft) {
                        lock.unlock();
                        continue;
                    }

                    this.takeLeft(forks);

                    boolean takeRight = this.checkRight(forks);
                    if (takeRight) {
                        this.takeRight(forks);
                    } else {
                        //放下fork
                        int right = this.right();
                        Phi rPhi = phis[forks[right] - 1];
                        //开始让出可用的fork
                        if (dirty[right] && !rPhi.getState().equals("Eating")) {
                            forks[right] = this.id;
                            dirty[right] = false;
                        } else {
                            lock.unlock();
                            continue;
                        }
                    }


                    lock.unlock();
                    this.eating();

                    lock.lockInterruptibly();
                    this.putLeft(forks);
                    this.putRight(forks);
                    dirty[this.left()] = true;
                    dirty[this.right()] = true;
                    lock.unlock();
                    this.finished();


                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            }
        }
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            new Thread(phis[i]).start();
        }
    }

    public static void main(String[] args) {
        DiningPhilosophersSample diningPhilosophersSample = new DiningPhilosophersSample();
        diningPhilosophersSample.run();
    }
}
